#pragma once

#include <linux/types.h>
#include <asm/page.h>
#include <riscv/pgtable-bits.h>

#define PGDIR_SHIFT_L3 30
#define PGDIR_SHIFT_L4 39
#define PGDIR_SHIFT_L5 48
#define PGDIR_SHIFT (PGDIR_SHIFT_L3)

/* Size of region mapped by a page global directory */
#define PGDIR_SIZE (1 << PGDIR_SHIFT)
#define PGDIR_MASK (~(PGDIR_SIZE - 1))

#define PMD_SHIFT 21
/* Size of region mapped by a page middle directory */
#define PMD_SIZE (1 << PMD_SHIFT)
#define PMD_MASK (~(PMD_SIZE - 1))

static inline int pgd_bad(pgd_t pgd)
{
    // TODO
    return 0;
}

static inline pgd_t pfn_pgd(unsigned long pfn, pgprot_t prot)
{
    unsigned long prot_val = pgprot_val(prot);

    return __pgd((pfn << _PAGE_PFN_SHIFT) | prot_val);
}

static inline int pte_none(pte_t pte)
{
	return (pte_val(pte) == 0);
}

#define _PAGE_KERNEL                            \
    (_PAGE_READ | _PAGE_WRITE | _PAGE_PRESENT | \
     _PAGE_ACCESSED | _PAGE_DIRTY | _PAGE_GLOBAL)

#define PAGE_KERNEL_EXEC __pgprot(_PAGE_KERNEL | _PAGE_EXEC)
#define PAGE_TABLE __pgprot(_PAGE_TABLE)

#define PTRS_PER_PGD (PAGE_SIZE / sizeof(pgd_t))
#define PTRS_PER_PMD (PAGE_SIZE / sizeof(pmd_t))
/* Number of entries in the page table */
#define PTRS_PER_PTE (PAGE_SIZE / sizeof(pte_t))

#define pmd_index(addr) (((addr) >> PMD_SHIFT) & (PTRS_PER_PMD - 1))

#define pmd_val(x)      ((x).pmd)
#define __pmd(x)        ((pmd_t) { (x) })

static inline int pmd_none(pmd_t pmd)
{
	return (pmd_val(pmd) == 0);
}

static inline pmd_t pfn_pmd(unsigned long pfn, pgprot_t prot)
{
	unsigned long prot_val = pgprot_val(prot);

	return __pmd((pfn << _PAGE_PFN_SHIFT) | prot_val);
}
